export * from './buffer'
export * from './string/index'
export * from './random/index'
export * from './time'
export * from './math'
export * as cache from './cache'
export * from './cookie'
export * from './type'
export * from './fetch'
type DebounceFunction<F extends (...args: unknown[]) => any> = (...args: Parameters<F>) => undefined

/**
 * 函数节流-立即执行版，
 * 触发的时候会立即执行一次,后续持续点击只会在单位时间内被点击触发一次
 */
export const throttleAtonce = <F extends (...args: unknown[]) => unknown>(
  func: F,
  delay: number
): DebounceFunction<F> => {
  let previous = 0
  return function (...args: Parameters<F>) {
    const now = Date.now()
    if (now - previous > delay) {
      func.call(this as string, args)
      previous = now
    }
  }
}

/**
 * 函数节流---延迟执行版,第一次触发会生成定时器，到一定时间后执行函数
 * 持续点击也只会在单位时间内触发一次
 */
export const throttleLatter = <F extends (...args: unknown[]) => unknown>(
  func: F,
  delay: number
): DebounceFunction<F> => {
  let timeout: number | undefined
  return function () {
    if (!timeout) {
      timeout = setTimeout(function () {
        func.call(this)
        timeout = void 0
      }, delay)
    }
  }
}

/**
 * 创建一个防抖函数
 * 事件触发过了一段时间之后才会执行，持续触发的话刷新计时器
 * @param func 需要进行防抖处理的函数
 * @param delay 防抖的延迟时间（毫秒）
 * @returns 防抖后的函数
 */
export function debounce<F extends (...args: unknown[]) => unknown>(
  func: F,
  delay: number
): DebounceFunction<F> {
  let timer: ReturnType<typeof setTimeout> | null = null

  return function (this: ThisParameterType<F>, ...args: Parameters<F>) {
    if (timer) clearTimeout(timer)

    timer = setTimeout(() => {
      timer = null
      return func.apply(this, args)
    }, delay)
  }
}

interface base64Result {
  status: 'error' | 'ok'
  message?: 'base64格式错误' | '无法获取图片类型' | '未知错误'
  blob?: Blob
  e?: unknown
}
/**
 * base64转化为图片
 */
export function base64ToBlob(base64: string): base64Result {
  try {
    const arr = base64.split(',')
    if (arr.length < 2) {
      return {
        status: 'error',
        message: 'base64格式错误',
      }
    }
    const regResult = arr[0].match(/:(.*?);/)
    if (!regResult) {
      return {
        status: 'error',
        message: '无法获取图片类型',
      }
    }
    const mime = regResult[1]
    const bstr = atob(arr[1])
    let n = bstr.length
    const u8arr = new Uint8Array(n)
    while (n--) {
      u8arr[n] = bstr.charCodeAt(n)
    }
    return {
      status: 'error',
      blob: new Blob([u8arr], {
        type: mime,
      }),
    }
  } catch (e) {
    return {
      status: 'error',
      message: '未知错误',
      e,
    }
  }
}

// 降级的复制
function defaultCopy(value: string): Promise<void> {
  return new Promise((resolve, reject) => {
    const element = document.createElement('textarea')
    element.style.opacity = '0'
    element.style.position = 'fixed'
    element.style.zIndex = '0'
    document.body.appendChild(element)
    element.value = value
    element.select()
    if (typeof document.execCommand !== 'function') {
      reject()
    }
    document.execCommand('copy')
    document.body.removeChild(element)
    resolve()
  })
}
/**
 * 赋值内容到剪切板,可以接受第二参数为复制成功的回调
 * 会先调用navigator.clipboard.writeText复制
 * 不存在就降级为document.execCommand('copy')
 * 需要用户操作之后才会复制成功
 */
export function copy(value: string): Promise<void> {
  return new Promise(resolve => {
    const { clipboard } = window.navigator
    if (clipboard instanceof Object && typeof clipboard.writeText === 'function') {
      clipboard
        .writeText(value)
        .then(resolve)
        .catch(e => {
          if (e.name === 'NotAllowedError') {
            return console.warn('需要点击之类的操作才可以触发')
          }
          return defaultCopy(value)
        })
    } else {
      return defaultCopy(value)
    }
  })
}

/**
 * 定时任务 返回promise，经过若干秒后触发
 */
export function sleep(time = 500): Promise<number> {
  return new Promise(resolve => setTimeout(() => resolve(time), time))
}
